﻿using System.Diagnostics;
using System.IO.Compression;

namespace Update
{
    public static class UpdateHelper
    {
        /// <summary>
        /// 远程更新
        /// </summary>
        /// <param name="args"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public static async Task RemoteUpdate(string[] args, CancellationToken cancellationToken)
        {
            if (args.Length < 2)
            {
                Console.WriteLine("参数错误。用法: Update.exe <共享ZIP路径> <主程序名> <已下载完的程序包> <自定义文件夹路径>");
                Console.ReadLine();
                return;
            }
            string remoteZipPath = args[0];
            string mainAppName = args[1];
            var zipPath = args.Length >= 3 ? args[2] : string.Empty;
            var customPath = args.Length >= 4 ? args[3] : string.Empty;
            var tempZipPath = string.Empty;
            if (!string.IsNullOrEmpty(zipPath))
            {
                if (File.Exists(zipPath))
                {
                    tempZipPath = zipPath;
                }
            }
            if (string.IsNullOrEmpty(tempZipPath))
            {
                Console.WriteLine("正在下载更新包...");
                tempZipPath = Path.Combine(Path.GetTempPath(), Path.GetFileName(remoteZipPath)); // 临时zip路径
                using var httpClient = new HttpClient();
                // 设置超时时间（可选）
                httpClient.Timeout = TimeSpan.FromMinutes(30);

                using var response = await httpClient.GetAsync(remoteZipPath, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
                response.EnsureSuccessStatusCode(); // 确保响应成功

                long? totalBytes = response.Content.Headers.ContentLength;

                using var contentStream = await response.Content.ReadAsStreamAsync(cancellationToken);
                using var fileStream = new FileStream(tempZipPath, FileMode.Create, FileAccess.Write);
                Console.ForegroundColor = ConsoleColor.Green;
                await ProcessContentStream(totalBytes, contentStream, fileStream, cancellationToken);
                Console.ForegroundColor = ConsoleColor.White;
                contentStream.Close();
                contentStream.Dispose();
                fileStream.Close();
                fileStream.Dispose();
            }
            var noDeleteList = new List<string>() {
                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"),
                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "markdown"),
                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources"),
                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WorkTool"),
                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Update.exe"),
                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, mainAppName)
            };
            if (!string.IsNullOrEmpty(customPath))
            {
                noDeleteList.Add(customPath);
                noDeleteList.Add(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, customPath));
            }
            DeleteAndExtract(tempZipPath, noDeleteList); // 删除并解压文件
            Console.WriteLine("正在启动主程序...");
            Process.Start(new ProcessStartInfo() { FileName = mainAppName, UseShellExecute = true });
        }

        private static async Task ProcessContentStream(long? totalBytes, Stream contentStream, FileStream fileStream, CancellationToken cancellationToken)
        {
            long totalRead = 0;
            long readCount = 0;
            byte[] buffer = new byte[8192]; // 8KB 缓冲区
            bool isMoreToRead = true;
            while (isMoreToRead)
            {
                // 检查是否请求取消
                cancellationToken.ThrowIfCancellationRequested();

                int read = await contentStream.ReadAsync(buffer, cancellationToken);
                if (read == 0)
                {
                    isMoreToRead = false;
                }
                else
                {
                    await fileStream.WriteAsync(buffer.AsMemory(0, read), cancellationToken);

                    totalRead += read;
                    readCount++;

                    // 每读取一定次数后更新一次UI，避免过于频繁的调用
                    if (readCount % 10 == 0)
                    {
                        await UpdateProgressAsync(totalBytes, totalRead);
                    }
                }
            }
            // 最后确保进度条到100%
            await UpdateProgressAsync(totalBytes, totalRead);
            ConsoleWriteLine("下载完成: 100%");
        }

        private static async Task UpdateProgressAsync(long? totalBytes, long totalRead)
        {
            if (totalBytes.HasValue)
            {
                int progressPercentage = (int)((totalRead * 100) / totalBytes.Value);
                ConsoleWriteLine($"下载中: {progressPercentage}%，已完成{FormatFileSize(totalRead)}");
            }
            else
            {
                int pulseProgress = (int)((totalRead / 1024) % 100); // 基于下载量的简单脉冲
                ConsoleWriteLine($"下载中: {pulseProgress}%，已完成{FormatFileSize(totalRead)}");
            }
            // 添加一个很小的延迟，让UI有机会更新
            await Task.Delay(1);
        }

        /// <summary>
        /// 格式化文件大小
        /// </summary>
        private static string FormatFileSize(long bytes)
        {
            string[] sizes = { "B", "KB", "MB", "GB" };
            int order = 0;
            double len = bytes;
            while (len >= 1024 && order < sizes.Length - 1)
            {
                order++;
                len = len / 1024;
            }
            return $"{len:0.##} {sizes[order]}";
        }

        public static void DeleteAndExtract(string tempZipPath, List<string> noDeleteList)
        {
            var currentPath = AppDomain.CurrentDomain.BaseDirectory;
            var zipFolderFiles = new List<string>();
            using (ZipArchive archive = ZipFile.OpenRead(tempZipPath))
            {
                foreach (ZipArchiveEntry entry in archive.Entries)
                {
                    var temp = entry.FullName.Split('/');
                    if (temp.Length > 0)
                        zipFolderFiles.Add(temp[0]);
                    else
                        zipFolderFiles.Add(entry.FullName);
                }
            }
            zipFolderFiles = [.. zipFolderFiles.Select(x => Path.Combine(currentPath, x)).Distinct()];
            zipFolderFiles.AddRange(noDeleteList);
            var directories = Directory.GetDirectories(currentPath);
            var files = Directory.GetFiles(currentPath);
            foreach (var directory in directories)
            {
                if (!zipFolderFiles.Contains(directory))
                {
                    ConsoleWriteLine($"正在删除 {directory} ...");
                    Directory.Delete(directory, true);
                }
            }
            foreach (var file in files)
            {
                if (!zipFolderFiles.Contains(file))
                {
                    ConsoleWriteLine($"正在删除 {file} ...");
                    File.Delete(file);
                }
            }
            Console.WriteLine("正在解压文件...");
            ZipFile.ExtractToDirectory(tempZipPath, Directory.GetCurrentDirectory(), true);
            Console.WriteLine("更新成功！");
            File.Delete(tempZipPath);
        }

        private static void ConsoleWriteLine(string message)
        {
            Console.SetCursorPosition(0, 1);
            Console.Write("\x1B[2K");
            Console.WriteLine(message);
        }
    }
}